package com.framework.common.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author sdy
 * @description
 * @date 2025/2/6
 */
@Slf4j
public class HttpUtils {

    private static final ConcurrentHashMap<String, OkHttpClient> clients = new ConcurrentHashMap<String, OkHttpClient>();

    private static final int connect_timeout = 30;
    private static final int read_timeout = 30;
    private static final int write_timeout = 30;
    private static final String METHOD_POST = "POST";
    private static final String METHOD_GET = "GET";
    private static final String MEDIA_TYPE = "application/json";
    private static final String DEFAULT_CHARSET = "UTF-8";

    public static String get(String url) {
        return get(url, null, null);
    }

    public static String get(String url, Map<String, String> headers, Map<String, String> params) {
        if (!CollectionUtil.isEmpty(params)) {
            url += "?" + parseGetParams(params);
        }
        return execute(METHOD_GET, url, MEDIA_TYPE, headers, null);
    }

    public static String post(String url, Object body) {
        return post(url, null, body);
    }

    public static String post(String url, String body) {
        return post(url, null, body);
    }

    public static String post(String url, Map<String, String> headers, Object body) {
        return post(url, headers, JSONUtil.toJsonStr(body));
    }

    public static String post(String url, Map<String, String> headers, String body) {
        return execute(METHOD_POST, url, MEDIA_TYPE, headers, body);
    }

    private static String execute(String methodType, String url, String medialType, Map<String, String> headers, String content) {
        Response response = null;
        try {
            URL netUrl = new URL(url);
            String key = String.format("%s:%d", netUrl.getHost(), netUrl.getPort());
            OkHttpClient okHttpClient = getOkHttpClient(key, 0, 10000L);
            if (METHOD_GET.equals(methodType)) {
                response = okHttpClient.newCall(buildRequest(netUrl, headers)
                                .get()
                                .build())
                        .execute();
            } else if (METHOD_POST.equals(methodType)) {
                response = okHttpClient.newCall(buildRequest(netUrl, headers)
                                .post(RequestBody.create(MediaType.parse(medialType), content))
                                .build())
                        .execute();
            }
            if (response == null) {
                return null;
            }
            return getResponseAsString(response, "UTF-8");
        } catch (IOException ex) {
            throw new RuntimeException("请求异常：" + ex.getMessage());
        } finally {
            if (response != null) {
                //The response body must be closed
                response.close();
            }
        }
    }

    private static OkHttpClient getOkHttpClient(String key, int maxIdleConnections, long keepAliveDuration) throws IOException {
        OkHttpClient client = clients.get(key);
        if (client != null) {
            return client;
        }
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
        builder.connectTimeout(connect_timeout, TimeUnit.SECONDS)
                .readTimeout(read_timeout, TimeUnit.SECONDS)
                .writeTimeout(write_timeout, TimeUnit.SECONDS);
        if (maxIdleConnections > 0) {
            builder.connectionPool(new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MILLISECONDS));
        }
        client = builder.build();
        clients.put(key, client);
        return client;
    }

    private static Request.Builder buildRequest(URL url, Map<String, String> headers) {
        Request.Builder builder = new Request.Builder();
        builder.url(url);
        builder.header("Accept", "*/*");
        builder.header("Content-Type", MEDIA_TYPE);
        if (headers != null) {
            for (Map.Entry<String, String> header : headers.entrySet()) {
                builder.header(header.getKey(), header.getValue());
            }
        }
        return builder;
    }

    private static String getResponseAsString(Response response, String charset) throws IOException {
        InputStream body = response.body() == null ? null : response.body().byteStream();
        if (null == body || !response.isSuccessful()) {
            throw new IOException(response.code() + ":" + response.message());
        }
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        try {
            while (true) {
                final int read = body.read(buff);
                if (read == -1) {
                    break;
                }
                os.write(buff, 0, read);
            }
        } catch (IOException e) {
            throw e;
        }
        return os.toString(charset);
    }

    private static String parseGetParams(Map<String, String> params) {
        return params.entrySet().stream().map(entry -> {
            try {
                String key = URLEncoder.encode(entry.getKey(), DEFAULT_CHARSET);
                String value = URLEncoder.encode(entry.getValue(), DEFAULT_CHARSET);
                return key + "=" + value;
            } catch (Exception e) {
                return null;
            }
        }).filter(StringUtils::isNotBlank).collect(Collectors.joining("&"));
    }

}
